package controllers;

import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Observer;

import javax.swing.JOptionPane;

import model.EditLayersModel;
import model.LayerModel;
import model.SearchPhotoModel;
import model.UpdatePhotoLayersModel;
import model.ViewPhotoWithLayerModel;
import view.SearchResultGUI;
import view.ViewPhotoWithLayerGUI;
import client.CliMessage;

/**
 * The Class EditLayersController.
 * @author Tomer Elkayam
 */
public class EditLayersController extends AbstractController
{
	
	/** The edit layers view. */
	private SearchResultGUI editLayersView;
 	
	/** The edit layers model. */
	private EditLayersModel editLayersModel;
 
	/**  The action listeners for the buttons. */
	private HashMap <String,AbstractListener> listeners;
	
	/** The pressed button index. */
	private int pressedButtonIndex;

	/** The layer list. */
	private ArrayList<LayerModel> layerList;
 
	/**
	 * Instantiates a new edits the layers controller.
	 *
	 * @param editLayersView the edit layers view
	 * @param editLayersModel the edit layers model
	 */
	public EditLayersController(SearchResultGUI editLayersView,	EditLayersModel editLayersModel) 
	{
		super(editLayersView, editLayersModel);
		this.editLayersModel = editLayersModel;
		this.editLayersView = editLayersView;
		setActionListeners() ;
	}

	/* (non-Javadoc)
	 * @see client.IObserve#handleDBRequestSuccess()
	 */
	@Override
	public void handleDBRequestSuccess() 
	{
		//if delete has succeded - reset table with data
		SearchPhotoModel aPhoto = editLayersModel.getThePhotoWhoOwnsTheLayers().getaPhoto();
		String timestamp = aPhoto.getTimeStamp();
		int location = aPhoto.getLocation();
		String searchPhotoLayersQuery =	"search" 	+"SELECT lt.LayerType , lt.LayerName , pl.LinkToFile "
													+"FROM photos AS p , photolayer AS pl, layertypes AS lt "
													+"WHERE pl.TimeStamp = p.TimeStamp "
													+"AND pl.Location = p.Location "
													+"AND lt.LayerType = pl.LayerType "
													+"AND p.TimeStamp = '"+timestamp+"' "
													+"AND p.Location = "+location;
		sendToServer(searchPhotoLayersQuery);
	}

	/* (non-Javadoc)
	 * @see client.IObserve#handleNullSearchResult()
	 */
	@Override
	public void handleNullSearchResult() 
	{
		//After delete if there are no layers - display empty table
		editLayersView.setTableVisibilty(false);
		editLayersView.disposeTable();
		//Dispose the buttons
		editLayersView.disposeExistingButtons();
		editLayersView.clickBackButton();
		// The photo has no layers - display appropriate message
		editLayersView.displayInfoMessage("This photo has no layers", "No layers found",2);
	
	}

	/***
	 * if the photo has other layers but the deleted ones - they would be displayed
	 */
	@Override
	public void handleDBSearchResult(CliMessage dbResult) 
	{
		//get the layer type, name and the link to file and save it to the model
		layerList = new ArrayList<LayerModel>();
		srs = dbResult.getSrs();
		int nRows = srs.size();
		
		
		//get all tuples
		for(int i = 0 ; i < nRows ; i++)
		{
			// get a tuple
			HashMap<String, String> layerTuple = srs.get(i);
			
			//get the time stamp , location and the link to file
			int layerType = Integer.parseInt(layerTuple.get("LAYERTYPE"));
			String layerName = layerTuple.get("LAYERNAME");
			String linkToFile = layerTuple.get("LINKTOFILE");
			
			//set a photo detail class
			LayerModel layerDetails = new LayerModel(layerType,layerName,linkToFile) ;
			
			//add the photo details to the list
			layerList.add(layerDetails);
			
			//display for developer
			System.out.println( layerName+" "+layerType+" "+linkToFile);
			
		}
		editLayersModel.setLayerList(layerList);
		
		//After a layer delete - repaint the table
		String dataTable[][] = createDataTable(srs);
		editLayersView.setTable(getColumnNames(srs), dataTable);
		
		//set buttons according to user permissions
		String[] buttonNames;
		buttonNames = new String[2];
		buttonNames[0] = "View layer";
		buttonNames[1] = "Delete layer";
		
		//create all the buttons and save them to the model
		editLayersView.setAllbuttons(nRows, buttonNames);
		editLayersModel.setButtonNames(buttonNames);
		setActionListeners();
		
	}
	
	/**
	 * The listener for receiving "View layer" button click events.
	 * The object created with this class is registered with a component using the
	 * component's <code>addViewLayerListener<code> method. When
	 * the viewLayer event occurs, that object's appropriate
	 * method is invoked , and the layer is displayed upon the photo.
	 *
	 * @see ViewLayerEvent
	 */
	class ViewLayerListener extends AbstractListener 
	{
		
		/** The previous observer. */
		private Observer previousObserver;

		/**
		 * Instantiates a new view layer listener.
		 *
		 * @param editLayersController the edit layers controller
		 */
		public ViewLayerListener(Observer editLayersController) 
		{
			this.previousObserver = editLayersController;
		}

		@Override
		public void actionPerformed(ActionEvent e) 
		{
			
			pressedButtonIndex = Integer.parseInt(e.getActionCommand());	
			
			// Display the photo with the layer on top of it
			ViewPhotoWithLayerGUI viewPhotoView = new ViewPhotoWithLayerGUI();
			LayerModel theLayer = editLayersModel.getLayerList().get(pressedButtonIndex);
			SearchPhotoModel thePhoto  = editLayersModel.getThePhotoWhoOwnsTheLayers().getaPhoto();
			ViewPhotoWithLayerModel thePhotoModel = new ViewPhotoWithLayerModel(thePhoto,theLayer);
			ViewPhotoWithLayerController vpc = new ViewPhotoWithLayerController(viewPhotoView,thePhotoModel);
			 
			 //set back listener and current observer
			 setCurrentObserver(vpc);
			 
			 setBackListener(previousObserver, viewPhotoView);
			 
			 String sql = "getphotoSELECT p.linktofile " 
						+" FROM photos AS p " 
						+" WHERE p.timestamp = '"+thePhotoModel.getThePhoto().getTimeStamp()+"'"
						+" AND p.location = "+thePhotoModel.getThePhoto().getLocation()
						+"<"
						+"SELECT pl.linktofile "
						+"FROM photos AS p , photolayer AS pl, layertypes AS lt "
						+"WHERE pl.TimeStamp = p.TimeStamp "
						+"AND pl.Location = p.Location "
						+"AND pl.LayerType = lt.LayerType "
						+"AND p.TimeStamp = '"+thePhotoModel.getThePhoto().getTimeStamp()+"' "
						+"AND p.Location = "+thePhotoModel.getThePhoto().getLocation()+" "
						+"AND lt.LayerName = '"+thePhotoModel.getTheLayer().getLayerName()+"'";;
	
			sendToServer(sql);
			
		}
	}
	
	/**
	 * The listener for receiving "Delete layer" button click events.
	 * The object created with that class is registered with a component using the
	 * component's <code>addDeleteListener<code> method. When
	 * the delete event occurs, that object's appropriate
	 * method is invoked and the user is prompted to confirm the layer delete.
	 * If the delete is confirmed the layer tuple is deleted from the db.
	 *
	 * @see DeleteEvent
	 */
	class DeleteListener extends AbstractListener 
	{
		@Override
		public void actionPerformed(ActionEvent e) 
		{
			pressedButtonIndex = Integer.parseInt(e.getActionCommand());	
			LayerModel theLayerToDelete = editLayersModel.getLayerList().get(pressedButtonIndex);
			String nameOfLayerToDelete = theLayerToDelete.getLayerName();
			// ask the user , are you sure?
			int result = JOptionPane.showConfirmDialog(editLayersView,
														"Are you sure you want to delete the layer '"+nameOfLayerToDelete+"' ?"
														, "Confirm Delete"
														, JOptionPane.YES_NO_OPTION,
														JOptionPane.WARNING_MESSAGE);
			//if the user has clicked "NO"  - return
			if(result !=JOptionPane.YES_OPTION)
				return;
			
			//get the photo details from the model and delete its layer from the db
			SearchPhotoModel thePhotoWhoOwnsTheLayer =  editLayersModel.getThePhotoWhoOwnsTheLayers().getaPhoto();
			String timestamp =thePhotoWhoOwnsTheLayer.getTimeStamp();
			int location = thePhotoWhoOwnsTheLayer.getLocation();
			String layerName = theLayerToDelete.getLayerName();
			String deleteQuery = "adu"	+"DELETE "
										+"FROM photolayer "
										+"WHERE timestamp = '"+timestamp+"' "
										+"AND location = " +location+" "
										+"AND layertype = ( SELECT layertype "
															+"FROM layertypes "
															+"WHERE layername = '"+layerName+"' )";
			System.out.println("delete query: \n" + deleteQuery);
			sendToServer(deleteQuery);
		}
	}
	
	
	/**
	 * Sets all the bottons action listeners.
	 */
	private void setActionListeners() 
	{
		listeners = new HashMap <String,AbstractListener>();
		listeners.put("View layer",new ViewLayerListener(this));
		listeners.put("Delete layer",new DeleteListener());
		
		String [] buttonNames =  editLayersModel.getButtonNames();
		int nRows = editLayersModel.getLayerList().size();
		
		for (int i = 0; i < nRows; i++) 
		{
			for (int j = 0; j < buttonNames.length; j++) 
			{
				editLayersView.addButtonListener(listeners.get(buttonNames[j]), buttonNames[j], i);
			}
		}
	}
	
	/**
	 * Creates the data table.
	 *
	 * @param srs the serialized result set
	 * @return the string[][]
	 */
	private String[][] createDataTable(ArrayList<HashMap<String, String>> srs)
	{
		int nRows = srs.size();
		int nCols = srs.get(0).keySet().size();
		
		//create data table
		 String[][] dataTable = new String[nRows][nCols];
		//get all keys
		 String[] columnNames = getColumnNames(srs);
		 	
		 //set data table
		 for (int j = 0; j < nRows; j++) 
		 {
			 for (int k = 0; k < nCols; k++) 
			 {
				 dataTable[j][k] = srs.get(j).get(columnNames[k]);
			 }
		 }
		 
		 return dataTable;
	}
	
	/**
	 * Gets the column names.
	 *
	 * @param srs the serialized result set
	 * @return the column names
	 */
	private String[] getColumnNames(ArrayList<HashMap<String, String>> srs)
	{
		int nCols = srs.get(0).keySet().size();
		 String[] columnNames = new String[nCols];
		 int i = 0;
		 for (String key : srs.get(0).keySet()) 
			 columnNames[i++] = key;
		 return columnNames;
	}
	

}
